package com.gobang.service.impl;

import com.gobang.service.ConnectionManagerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 连接管理服务实现类
 * 使用Redis存储和管理WebSocket连接状态信息
 * 
 * @author System
 * @since 1.0.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ConnectionManagerServiceImpl implements ConnectionManagerService {
    
    private final RedisTemplate<String, Object> redisTemplate;
    
    // Redis键前缀
    private static final String USER_ONLINE_PREFIX = "user:online:";
    private static final String WEBSOCKET_SESSIONS_KEY = "websocket:sessions";
    private static final String ROOM_USERS_PREFIX = "room:";
    
    // 连接过期时间（30分钟）
    private static final long CONNECTION_EXPIRE_TIME = 30;
    
    @Override
    public void addConnection(Long userId, String sessionId, String username, Integer currentScore) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            
            // 存储用户在线状态信息
            redisTemplate.opsForHash().putAll(userKey, Map.of(
                    "connection_id", sessionId,
                    "last_active", System.currentTimeMillis(),
                    "status", "online",
                    "username", username != null ? username : "",
                    "score", currentScore != null ? currentScore : 0
            ));
            
            // 设置过期时间
            redisTemplate.expire(userKey, CONNECTION_EXPIRE_TIME, TimeUnit.MINUTES);
            
            // 存储会话映射（session-user映射）
            redisTemplate.opsForHash().put(WEBSOCKET_SESSIONS_KEY, sessionId, userId);
            
            log.info("用户连接已添加: userId={}, sessionId={}, username={}", userId, sessionId, username);
        } catch (Exception e) {
            log.error("添加用户连接失败: userId={}, sessionId={}", userId, sessionId, e);
        }
    }
    
    @Override
    public void removeConnection(Long userId) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            
            // 获取会话ID
            String sessionId = (String) redisTemplate.opsForHash().get(userKey, "connection_id");
            
            // 删除用户在线信息
            redisTemplate.delete(userKey);
            
            // 删除会话映射
            if (sessionId != null) {
                redisTemplate.opsForHash().delete(WEBSOCKET_SESSIONS_KEY, sessionId);
            }
            
            log.info("用户连接已移除: userId={}, sessionId={}", userId, sessionId);
        } catch (Exception e) {
            log.error("移除用户连接失败: userId={}", userId, e);
        }
    }
    
    @Override
    public void removeConnectionBySession(String sessionId) {
        try {
            // 根据会话ID获取用户ID
            Long userId = getUserIdBySession(sessionId);
            if (userId != null) {
                removeConnection(userId);
            } else {
                // 如果找不到用户ID，直接删除会话映射
                redisTemplate.opsForHash().delete(WEBSOCKET_SESSIONS_KEY, sessionId);
                log.info("会话映射已删除: sessionId={}", sessionId);
            }
        } catch (Exception e) {
            log.error("根据会话ID移除连接失败: sessionId={}", sessionId, e);
        }
    }
    
    @Override
    public boolean isUserOnline(Long userId) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            return redisTemplate.hasKey(userKey);
        } catch (Exception e) {
            log.error("检查用户在线状态失败: userId={}", userId, e);
            return false;
        }
    }
    
    @Override
    public String getUserSession(Long userId) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            return (String) redisTemplate.opsForHash().get(userKey, "connection_id");
        } catch (Exception e) {
            log.error("获取用户会话ID失败: userId={}", userId, e);
            return null;
        }
    }
    
    @Override
    public Long getUserIdBySession(String sessionId) {
        try {
            Object userIdObj = redisTemplate.opsForHash().get(WEBSOCKET_SESSIONS_KEY, sessionId);
            if (userIdObj instanceof Number) {
                return ((Number) userIdObj).longValue();
            }
            return null;
        } catch (Exception e) {
            log.error("根据会话ID获取用户ID失败: sessionId={}", sessionId, e);
            return null;
        }
    }
    
    @Override
    public void updateLastActive(Long userId) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            if (redisTemplate.hasKey(userKey)) {
                // 更新最后活跃时间
                redisTemplate.opsForHash().put(userKey, "last_active", System.currentTimeMillis());
                // 刷新过期时间
                redisTemplate.expire(userKey, CONNECTION_EXPIRE_TIME, TimeUnit.MINUTES);
                log.debug("用户活跃时间已更新: userId={}", userId);
            }
        } catch (Exception e) {
            log.error("更新用户活跃时间失败: userId={}", userId, e);
        }
    }
    
    @Override
    public void updateUserStatus(Long userId, String status) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            if (redisTemplate.hasKey(userKey)) {
                redisTemplate.opsForHash().put(userKey, "status", status);
                log.debug("用户状态已更新: userId={}, status={}", userId, status);
            }
        } catch (Exception e) {
            log.error("更新用户状态失败: userId={}, status={}", userId, status, e);
        }
    }
    
    @Override
    public String getUserStatus(Long userId) {
        try {
            String userKey = USER_ONLINE_PREFIX + userId;
            return (String) redisTemplate.opsForHash().get(userKey, "status");
        } catch (Exception e) {
            log.error("获取用户状态失败: userId={}", userId, e);
            return null;
        }
    }
    
    @Override
    public Set<Long> getAllOnlineUsers() {
        try {
            Set<String> keys = redisTemplate.keys(USER_ONLINE_PREFIX + "*");
            Set<Long> userIds = new HashSet<>();
            if (keys != null) {
                for (String key : keys) {
                    String userIdStr = key.substring(USER_ONLINE_PREFIX.length());
                    try {
                        userIds.add(Long.parseLong(userIdStr));
                    } catch (NumberFormatException e) {
                        log.warn("无效的用户ID格式: {}", userIdStr);
                    }
                }
            }
            return userIds;
        } catch (Exception e) {
            log.error("获取所有在线用户失败", e);
            return new HashSet<>();
        }
    }
    
    @Override
    public Set<Long> getRoomUsers(String roomId) {
        try {
            String roomKey = ROOM_USERS_PREFIX + roomId + ":users";
            Set<Object> userObjects = redisTemplate.opsForSet().members(roomKey);
            Set<Long> userIds = new HashSet<>();
            if (userObjects != null) {
                for (Object userObj : userObjects) {
                    if (userObj instanceof Number) {
                        userIds.add(((Number) userObj).longValue());
                    }
                }
            }
            return userIds;
        } catch (Exception e) {
            log.error("获取房间用户列表失败: roomId={}", roomId, e);
            return new HashSet<>();
        }
    }
    
    @Override
    public void addUserToRoom(String roomId, Long userId) {
        try {
            String roomKey = ROOM_USERS_PREFIX + roomId + ":users";
            redisTemplate.opsForSet().add(roomKey, userId);
            // 设置房间过期时间（1小时）
            redisTemplate.expire(roomKey, 1, TimeUnit.HOURS);
            log.debug("用户已加入房间: roomId={}, userId={}", roomId, userId);
        } catch (Exception e) {
            log.error("用户加入房间失败: roomId={}, userId={}", roomId, userId, e);
        }
    }
    
    @Override
    public void removeUserFromRoom(String roomId, Long userId) {
        try {
            String roomKey = ROOM_USERS_PREFIX + roomId + ":users";
            redisTemplate.opsForSet().remove(roomKey, userId);
            log.debug("用户已离开房间: roomId={}, userId={}", roomId, userId);
        } catch (Exception e) {
            log.error("用户离开房间失败: roomId={}, userId={}", roomId, userId, e);
        }
    }
    
    @Override
    public void clearRoom(String roomId) {
        try {
            String roomKey = ROOM_USERS_PREFIX + roomId + ":users";
            redisTemplate.delete(roomKey);
            log.info("房间已清理: roomId={}", roomId);
        } catch (Exception e) {
            log.error("清理房间失败: roomId={}", roomId, e);
        }
    }
    
    @Override
    public Set<Long> getTimeoutConnections(long timeoutMs) {
        try {
            Set<Long> timeoutUsers = new HashSet<>();
            Set<Long> allUsers = getAllOnlineUsers();
            long currentTime = System.currentTimeMillis();
            
            for (Long userId : allUsers) {
                String userKey = USER_ONLINE_PREFIX + userId;
                Object lastActiveObj = redisTemplate.opsForHash().get(userKey, "last_active");
                if (lastActiveObj instanceof Number) {
                    long lastActive = ((Number) lastActiveObj).longValue();
                    if (currentTime - lastActive > timeoutMs) {
                        timeoutUsers.add(userId);
                    }
                }
            }
            
            return timeoutUsers;
        } catch (Exception e) {
            log.error("获取超时连接失败: timeoutMs={}", timeoutMs, e);
            return new HashSet<>();
        }
    }
    
    @Override
    public int cleanTimeoutConnections(long timeoutMs) {
        try {
            Set<Long> timeoutUsers = getTimeoutConnections(timeoutMs);
            for (Long userId : timeoutUsers) {
                removeConnection(userId);
            }
            log.info("已清理超时连接: count={}, timeoutMs={}", timeoutUsers.size(), timeoutMs);
            return timeoutUsers.size();
        } catch (Exception e) {
            log.error("清理超时连接失败: timeoutMs={}", timeoutMs, e);
            return 0;
        }
    }
} 